package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author brianxia
 * @version 1.0
 * @date 2022-10-30 14:43
 */
@Service
@Slf4j
public class HotArticleServiceImpl implements HotArticleService {

    @Autowired
    private ApArticleMapper apArticleMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void hotArticle() {
        //1.查询5天内文章 如果文章量级比较大，使用分片广播来处理
        LocalDate localDateTime = LocalDate.now().minusDays(5);
        List<ApArticle> apArticles = apArticleMapper.selectArticleListByDate(localDateTime);
        if(CollectionUtils.isEmpty(apArticles)){
            return;
        }

        //2.计算文章分值
        List<HotArticleVo> apArticleScore = computeScore(apArticles);

        //3.将数据缓存到redis中
        //缓存数据到推荐页（所有文章）  指定频道中  获取分值排名前30位文章，按照分值倒序排列，放到redis
        //调用远程接口获取所有频道（不太推荐）
        List<Integer> channelIds = apArticleScore.stream().filter(x -> x.getChannelId() != null)
                .map(ApArticle::getChannelId).distinct().collect(Collectors.toList());

        for (Integer channelId : channelIds) {
            List<HotArticleVo> list = apArticleScore.stream().filter(x -> channelId.equals(x.getChannelId()))
                    .collect(Collectors.toList());

            setHotArticleToRedis(list,channelId.toString());
        }

        setHotArticleToRedis(apArticleScore,ArticleConstants.DEFAULT_TAG);

    }

    private void setHotArticleToRedis(List<HotArticleVo> apArticleScore,String channelId) {
        List<HotArticleVo> list = apArticleScore.stream().
                sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .limit(30).collect(Collectors.toList());

        stringRedisTemplate.opsForValue().set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE
                + channelId, JSON.toJSONString(list));
    }

    private List<HotArticleVo> computeScore(List<ApArticle> apArticles) {
        List<HotArticleVo> result = new ArrayList<>();

        for (ApArticle apArticle : apArticles) {
            HotArticleVo hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle,hotArticleVo);

            //计算分值
            int score = computeArticleScore(apArticle);
            hotArticleVo.setScore(score);

            result.add(hotArticleVo);
        }

        return result;
    }

    private int computeArticleScore(ApArticle apArticle) {
        int score = 0;

        //阅读
        Integer views = apArticle.getViews();
        if(views != null){
            score += views * ArticleConstants.HOT_ARTICLE_VIEW_WEIGHT;
        }
        //点赞
        Integer likes = apArticle.getLikes();
        if(likes != null){
            score += likes * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        //收藏
        Integer collection = apArticle.getCollection();
        if(collection != null){
            score += collection * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        //评论
        Integer comment = apArticle.getComment();
        if(comment != null){
            score += comment * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }

        return score;
    }

    public static void main(String[] args) {
        //1.通过Calendar进行计算
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DAY_OF_MONTH,-5);
        Date time = instance.getTime();
        System.out.println(time);

        //2.jdk1.8自带localdate
        LocalDateTime localDateTime = LocalDateTime.now().minusDays(5);
        System.out.println(localDateTime);

        //3.老版本jdk没有localdate
        //使用第三方joda-time
        Date date = DateTime.now().minusDays(5).toDate();
        System.out.println(date);
    }
}
